/**
 * 
 */
package truerefactor.refactor;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import truerefactor.graph.ClassNode;
import truerefactor.graph.CodeGraph;
import truerefactor.graph.CodeNode;
import truerefactor.graph.MethodNode;
import truerefactor.metrics.WMC;

/**
 * An Implementation of the Inline Method Refactoring Technique
 * 
 * @author Isaac
 */
public class InlineMethod extends Refactoring {

    /**
     * 
     */
    public InlineMethod()
    {
        this.shortName = "INMETH";
        this.name = "Inline Method";
        this.description = "";
    }

    /*
     * (non-Javadoc)
     * @see
     * truerefactor.refactor.Refactoring#execute(truerefactor.graph.CodeNode [])
     */
    @Override
    public void execute(CodeGraph graph)
    {
        MethodNode toInline = (MethodNode) operands.get(0);
        ClassNode source = toInline.getParentClass();
        // 1. Check that the method is not polymorphic
        // a. Don't inline if subclasses override the method; they cannot
        // override a method that isn't there.
        List<ClassNode> subClasses = source.getSubClasses();
        for (ClassNode sub : subClasses)
        {
            List<MethodNode> methods = sub.getMethodsByName(toInline.getIdentifier());
            if (!methods.isEmpty())
            {
                for (MethodNode override : methods)
                {
                    if (override.getIdentifier().equals(toInline.getIdentifier()))
                    {
                        if (override.getParameters().size() == toInline.getParameters().size())
                        {
                            if (override.getReturnType().equals(toInline.getReturnType()))
                                return;
                        }
                    }
                }
            }
        }

        // 5. Don't inline a method that is very complex (multiple return
        // points, recursion, objects without accessors, ect.)
        if (WMC.calcComplexity(toInline) > 4)
            return;

        // 2. Find all calls to the method
        Set<MethodNode> allCallers = new HashSet<MethodNode>();
        allCallers.addAll(toInline.getAssociatedMethods());
        allCallers.addAll(toInline.getOtherMethods());

        // 3. Replace each call with the method body
        // TODO: Figure this out, should be quite simple just copy the statement nodes from the toInline's statement graph inline above the place where it is called.
        //       then determine whether it is a call, or a call returning a value
        //       if returning a value then remove the return statment and copy the right hand side of the calling statement and set it equal to the rest of the statement after the return keyword
        //       Handle parameters by examining eah parameer passed in and finding the statements related to it and changing the names/values as required in the code being copied over.

        // 4. Remove the method definition
        graph.remove(toInline);
    }
}
